/*
 * (c) 2012 Leonid Bensman, lbensman.cs00@gtalumni.org
 */
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;

namespace CalcSig
{
    class DirectoryEnumerator
    {
        private readonly IEnumerable<string> searchTargets;
        private readonly IEnumerable<string> excludeTargets;
        private readonly IEnumerable<string> defaultSearchMasks;
        private readonly bool recursive;

        public DirectoryEnumerator(IEnumerable<string> searchTargets, IEnumerable<string> defaultSearchMasks, IEnumerable<string> excludeTargets, bool recursive)
        {
            this.searchTargets = searchTargets;
            this.defaultSearchMasks = defaultSearchMasks;
            this.excludeTargets = excludeTargets;
            this.recursive = recursive;
        }

        public IEnumerable<string> Enumerate()
        {
            // First find all the exclude files (in case there are any, and assuming small list)
            List<Regex> excludedMatchRegexes = new List<Regex>();
                     
            foreach(string excludeMask in this.excludeTargets)
            {
                excludedMatchRegexes.Add(new Regex(maskToRegex(excludeMask)));
            }

            foreach (string searchTarget in this.searchTargets)
            {
                string targetFolder = Path.GetDirectoryName(searchTarget);
                string targetSearchMaskPart = Path.GetFileName(searchTarget);
                List<string> targetSearchMasks;

                if (string.IsNullOrEmpty(targetSearchMaskPart))
                {
                    targetSearchMasks = new List<string>(this.defaultSearchMasks);
                }
                else
                {
                    targetSearchMasks = new List<string>();
                    targetSearchMasks.Add(targetSearchMaskPart);
                }

                foreach(string targetSearchMask in targetSearchMasks)
                {
                    foreach (string file in Directory.GetFiles(targetFolder, targetSearchMask, recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly))
                    {
                        bool exclude = false;

                        foreach(Regex exclusionRegex in excludedMatchRegexes)
                        {
                            if (exclusionRegex.IsMatch(file))
                            {
                                exclude = true;
                                break;
                            }
                        }

                        if(exclude)
                        {
                            continue;
                        }

                        yield return file;
                    }
                }
            }
        }

        private string maskToRegex(string mask)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append('^');

            foreach (char c in mask)
            {
                switch (c)
                {
                    //case '.': 
                    //    sb.Append(@"\."); 
                    //    break;
                    case '*': 
                        sb.Append(@".*"); 
                        break;
                    case '?': 
                        sb.Append(@"."); 
                        break;
                    default:
                        sb.Append(Regex.Escape(c.ToString()));
                        break;
                }
            }

            sb.Append('$');

            return sb.ToString();
        }
    }
}
